﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Threading;
using System.Windows.Threading;

namespace SkypeStudio.Framework
{

    public abstract class NotifyPropertyChangedBase : INotifyPropertyChanged
    {
        private void RaisePropertyChangedEventCore(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
        /// <summary>
        ///   Notifies subscribers of the property change.
        /// </summary>
        /// <param name = "propertyName">Name of the property.</param>
        protected virtual void NotifyOfPropertyChange(string propertyName)
        {
            RaisePropertyChangedEventCore(propertyName);
            //Execute.OnUIThread(() =>);
        }

        /// <summary>
        ///   Notifies subscribers of the property change.
        /// </summary>
        /// <typeparam name = "TProperty">The type of the property.</typeparam>
        /// <param name = "property">The property expression.</param>
        protected virtual void NotifyOfPropertyChange<TProperty>(Expression<Func<TProperty>> property)
        {
            NotifyOfPropertyChange(property.GetMemberInfo().Name);
        }


        public event PropertyChangedEventHandler PropertyChanged;
    }
    public abstract class ViewModelBase<TView> : NotifyPropertyChangedBase where TView : IView 
    {
        private readonly TView _View;

        public ViewModelBase(TView view)
            : this(view, false)
        {
        }

        public ViewModelBase(TView view, bool isChild)
        {
            if (view == null) { throw new ArgumentNullException("view"); }
            this._View = view;
            if (!isChild)
            {
                // Check if the code is running within the WPF application model
                if (SynchronizationContext.Current is DispatcherSynchronizationContext)
                {
                    // Set DataContext of the view has to be delayed so that the ViewModel can initialize the internal data (e.g. Commands)
                    // before the view starts with DataBinding.
                    Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate()
                    {
                        _View.DataContext = this;
                    });
                }
                else
                {
                    // When the code runs outside of the WPF application model then we expect that this constructor is called
                    // within a unit test. Therefore, we don't need the Dispatcher here.
                    view.DataContext = this;
                }
            }
        }

  
        public IView View
        {
            get
            {
                return _View;
            }
        }
            
    }
}
